home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / programming / source / jpegagasrc11.lha / jpegagasrc / ppm2aga / ppm2ilbm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-06  |  27.8 KB  |  940 lines

  1. /* ppm2ilbm module                 */
  2. /* written by Günther Röhrich      */
  3. /* this is version 1.4             */
  4.  
  5. /* this code is tested with Aztec C 5.2a and GNU C 2.5.8 */
  6. /* NOTE: you will need the newiff V37 or higher package */
  7. /* (V37 is available on Fish-disk 705) */
  8.  
  9.  
  10. #include <clib/exec_protos.h>
  11. #include <libraries/iffparse.h>
  12. #include <dos/dos.h>
  13. #include <iffp/ilbmapp.h>
  14. #include <iffp/packer.h>
  15. #include <stdio.h>
  16. #include <graphics/modeid.h>
  17.  
  18. #include "ppm2AGA.h"
  19.  
  20. #ifndef __GNUC__
  21. #include <pragmas/exec_pragmas.h>
  22. #include <pragmas/iffparse_pragmas.h>
  23. #endif
  24.  
  25.  
  26.  
  27. /* needed when compiling with newiff V37 package */
  28. /* (not needed with V39 or higher) */
  29.  
  30. #ifndef BMHDF_CMAPOK
  31. #define BMHDF_CMAPOK (1 << 7)
  32. #endif
  33.  
  34.  
  35. /* externals used by this module */
  36.  
  37.  
  38. extern int AbortCheck(void);
  39. extern void PLProgress(ULONG Value, ULONG MaxValue);
  40. extern volatile unsigned short MaxError, MaxErrorPos;
  41. extern void EncodeHAM(UBYTE *yorig, UBYTE *yham, char *ColorTable, 
  42.                        short NumColors, short xsize);
  43. extern int MapColorASM(colorhist_vector colormap, pixval r1, pixval g1, pixval b1, 
  44.              int NumColors);
  45. extern int ExactColor;
  46. extern int GfxEnable;
  47. extern int VGAenable;
  48. extern int jpegAGA;
  49. extern char *ILBMfile;
  50. extern ULONG SMR;
  51. extern ULONG SMR_DisplayID;
  52.  
  53. /* definitions for the display routines */
  54.  
  55. extern int InitDisplay(int cols, int rows, ULONG Mode, int NumPlanes);
  56. extern void SetDisplayColor(int ColorNumber, UBYTE r, UBYTE g, UBYTE b);
  57. extern void DisplayRow(char *array, int cols, int row);
  58. extern void CloseDisplay(void);
  59.  
  60. /* globals defined in this module */
  61.  
  62. #ifdef DEBUG_ASM
  63. int MapColor(colorhist_vector colormap, pixval r1, pixval g1, pixval b1, 
  64.              int NumColors);
  65. #endif
  66.  
  67. unsigned short Mult_Table[2*256];
  68. unsigned long  Mult_Table32[2*256];
  69. jmp_buf ErrorEnv;
  70. int cols, rows, rowcnt;
  71. pixel **pixels;
  72. pixel *pixrow;
  73. pixval maxval;
  74. int ppmformat;
  75. char ColorTable[64*3] = {0};
  76. int ColorRegMax; 
  77. unsigned short ConvertMode;
  78. char *ColorCache; /* a 256K cache for EncodeHAM() */
  79.  
  80. /* these are needed by Floyd-Steinberg-routines */
  81. long  *thisrerr;
  82. long  *nextrerr;
  83. long  *thisgerr;
  84. long  *nextgerr;
  85. long  *thisberr; 
  86. long  *nextberr;     
  87. extern int floyd; 
  88. int fs_direction = 1;
  89. int Convert4096;
  90. int Convert262144;
  91. #define FS_SCALE 1024
  92.  
  93. /* locals defined in this module */
  94.  
  95. static FILE *fppm;
  96. static FILE *ColorMapFile;
  97. static struct IFFHandle *iff;
  98. static struct ILBMInfo ilbm;
  99. static int error;
  100. static LONG IFFError;
  101. static unsigned char *coded_rowbuf;
  102. static unsigned char *hamarray;
  103. static int returnvalue;
  104. static void ppmCleanUp(void);
  105. static int readall;
  106. static colorhist_vector chv, colormap;
  107. static BYTE *CompressBuffer;
  108. static void encode_row(UBYTE *row, int cols, int nPlanes);
  109. static int ColorShift, NumColors;
  110. static gray *pgmrow;
  111.  
  112. static int lumcompare(colorhist_vector ch1, colorhist_vector ch2)
  113. {
  114.  return (int)((double)PPM_LUMIN(ch1->color) - (double)PPM_LUMIN(ch2->color));
  115. }
  116.  
  117.  
  118. int ppm2ilbm(char *PPMfile, ULONG Mode, int NumPlanes, ULONG MaxMem)
  119. {
  120.  int i, colors;
  121.  pixel *pP;
  122.  unsigned short AbsMaxError = 0;
  123.  unsigned short MaxErrorXPos = 0;
  124.  unsigned short MaxErrorYPos = 0;
  125.  
  126.  /* initialize everything                            */
  127.  /* this is needed because we may call this function */
  128.  /* multiple times                                   */
  129.  returnvalue = 0;
  130.  fppm = NULL;
  131.  ColorMapFile = NULL;
  132.  readall = 0;
  133.  pixrow = NULL;
  134.  pixels = NULL;
  135.  hamarray = NULL; coded_rowbuf = NULL; ColorCache=NULL; 
  136.  memset(&ilbm, 0, sizeof(struct ILBMInfo)); 
  137.  chv = NULL;
  138.  colormap = NULL;
  139.  CompressBuffer = NULL;
  140.  pgmrow = NULL;
  141.  
  142.  
  143.  /* multiplication table is needed by assembler subroutines */
  144.  for(i=-255; i<256; i++)
  145.  {
  146.    Mult_Table[i+255] = i*i;
  147.    Mult_Table32[i+255] = i*i;
  148.  }
  149.  
  150.  
  151.  /* if we encounter an error we longjmp() to this location       */
  152.  /* the ppmCleanUp() function will free all resources  allocated */
  153.  /* in this module                                               */
  154.  
  155.  error = setjmp(ErrorEnv);
  156.  if(error != 0) 
  157.  {
  158.   ppmCleanUp();
  159.   return error;
  160.  }  
  161.  
  162.  
  163.  /* try to open the ppm file */
  164.  fppm = fopen(PPMfile, "r");
  165.  if(!fppm) pm_error("Could not open file %s\n", PPMfile);
  166.  
  167.  /* read the header of the ppm file */
  168.  ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat); 
  169.  
  170.  #ifdef DEBUG
  171.  pm_message("Cols: %d, Rows: %d, MaxVal: %d, Format: %d\n",
  172.              cols, rows, maxval, ppmformat);
  173.  #else
  174.  pm_message("Cols: %d, Rows: %d, MaxVal: %d\n", cols, rows, maxval);
  175.  #endif
  176.  
  177.  /* Initialize Floyd-Steinberg error vectors. */
  178.  thisrerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  179.  nextrerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  180.  thisgerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  181.  nextgerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  182.  thisberr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  183.  nextberr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  184.  srandom( (int) ( time( 0 ) ^ getpid(0) ) );
  185.  for ( i = 0; i < cols + 2; ++i )
  186.  {
  187.    thisrerr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  188.    thisgerr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  189.    thisberr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  190.    /* (random errors in [-1 .. 1]) */ 
  191.  }
  192.  
  193.  /* try to open the output file */
  194.  
  195.  if(!jpegAGA)
  196.  {
  197.    if(!(ilbm.ParseInfo.iff = AllocIFF()))
  198.      pm_error("Could not do AllocIFF()");
  199.  
  200.    iff = ilbm.ParseInfo.iff;
  201.  
  202.    IFFError = openifile((struct ParseInfo *)&ilbm, (UBYTE *)ILBMfile, IFFF_WRITE);
  203.    if(IFFError) pm_error(""); /* openifile() will print error messages... */
  204.  }
  205.  
  206.  if(Mode == HAM8 || Mode == HAM6 || Mode == COLORMAP)
  207.  {
  208.    int Clustering;
  209.    if(Mode == HAM8)
  210.    {
  211.      NumColors = NumPlanes;
  212.      ColorRegMax  = 63;
  213.      ColorShift   = 2; /* we only have 256K colors */
  214.      NumPlanes    = 8;
  215.      ConvertMode  = 1; /* Needed by EncodeHAM() */
  216.      Clustering   = 0;
  217.      Convert4096  = 0; /* No 4096-FS conversion */
  218.      if(floyd) Convert262144 = 1; /* 262144 conversion */
  219.     
  220.    }
  221.    else if(Mode == HAM6)
  222.    {
  223.      NumColors = NumPlanes;
  224.      ColorRegMax = 15; 
  225.      ColorShift  = 4; /* converting to 4096 colors will be done by FS dithering */
  226.      NumPlanes   = 6;
  227.      ConvertMode = 0; /* Needed by EncodeHAM() */
  228.      Clustering  = 0;
  229.      if(floyd)
  230.        Convert4096 = 1; /* Do 4096-FS conversion */
  231.      Convert262144 = 0;
  232.    }
  233.    else /* COLORMAP */
  234.    { 
  235.      NumColors = 1 << NumPlanes;      
  236.      ColorRegMax = 255;
  237.      ColorShift = 0; /* we will handle full 16M colors */
  238.      if(ppmformat == PGM_FORMAT || ppmformat == RPGM_FORMAT || ExactColor == 1)
  239.      {
  240.        Clustering = 0;
  241.      }
  242.      else
  243.      {
  244.        Clustering = 2;
  245.      }
  246.      Convert4096 = 0; /* No 4096-FS conversion */
  247.      Convert262144 = 0;
  248.    } 
  249.        
  250.    if( cols*rows*3 <= (int)MaxMem)
  251.    {     
  252.      /* read the complete picture into memory */
  253.      int row;
  254.      readall = 1;
  255.      pm_message("Reading complete picture into memory...\n");
  256.      pixels = ppm_allocarray(cols, rows);     
  257.      for(row = 0; row < rows; ++row)
  258.      {
  259.        if(AbortCheck()) pm_error("^C\n");
  260.        ppm_readppmrow(fppm, pixels[row], cols, maxval, ppmformat);
  261.        if(maxval != ColorRegMax)
  262.        {
  263.          if(maxval == 255)
  264.          {
  265.            for(i=0, pP=pixels[row]; i < cols; ++i, ++pP)
  266.            {
  267.              pP->r = pP->r >> ColorShift;
  268.              pP->g = pP->g >> ColorShift;
  269.              pP->b = pP->b >> ColorShift;
  270.            }
  271.          }
  272.          else
  273.          {
  274.            for(i=0, pP=pixels[row]; i < cols; ++i, ++pP)
  275.              PPM_DEPTH(*pP, *pP, maxval, ColorRegMax);
  276.          }
  277.        }
  278.      }
  279.    }
  280.    else
  281.    {
  282.      rowcnt = 0;
  283.      if(!(pixrow = ppm_allocrow(cols)))
  284.        pm_error("Out of memory.\n");     
  285.     }
  286.  
  287.  
  288.    /* allocate enough room for one row of chunky HAM pixels  */
  289.    /* (this array will also be used for colormap conversion) */
  290.    if(!(hamarray = malloc(RowBits(cols))))
  291.      pm_error("Out of memory.\n");
  292.  
  293.    /* we only have to clear the space between cols and RowBits(cols)    */
  294.    /* hamarray will be larger in most cases because of special alignment*/
  295.    for(i = cols; i < RowBits(cols); i++) hamarray[i] = 0;
  296.    pm_message("Computing colormap...\n");
  297.  
  298.  
  299.    /* now we make a histogram of the picture...          */
  300.    /* if we increase Clustering we will find less colors */
  301.    /* we allow a maximum of 10000 colors                 */
  302.    /* ColorShift is the shift needed for HAM encoding    */
  303.    for(i=Clustering; i<5; i++)
  304.    {
  305.      if((chv = ppm_fcomputecolorhist(fppm, cols, rows, 10000, &colors, ColorShift, i)))
  306.        break;
  307.      if(AbortCheck()) pm_error("^C\n");
  308.      pm_message("Could not compute colormap, trying again...\n");
  309.      rowcnt=0;
  310.      if(!readall)
  311.      { 
  312.        rewind(fppm); /* re-initialise the ppm pointers for reading again */
  313.        ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);       
  314.      }
  315.    } 
  316.  
  317.    pm_message("Found %d colors.\n", colors);
  318.  
  319.  
  320.    /* now we try to find a suitable colormap... */
  321.    colormap = mediancut(chv, colors, rows*cols, ColorRegMax, NumColors);
  322.    ppm_freecolorhist(chv); /* we don't need the histogram any more */
  323.    chv = NULL;
  324.    /* sort the colors in ascending luminance order...  */ 
  325.    /* (the first color will be the background color)      */
  326.    if(NumColors < colors)
  327.    {
  328.      qsort((char *)colormap, NumColors, sizeof(struct colorhist_item), lumcompare);
  329.    }
  330.    else
  331.    {
  332.      qsort((char *)colormap, colors, sizeof(struct colorhist_item), lumcompare);
  333.    }
  334.  
  335.    
  336.    if(!jpegAGA)
  337.    {   
  338.      /* the CompressBuffer is needed by the cmpByteRun1 compressor */
  339.      if(!(CompressBuffer = malloc(MaxPackedSize(RowBytes(cols)))))
  340.        pm_error("Out of memory allocating the compress buffer.\n");
  341.  
  342.      /* the ColorCache is needed by EncodeHAM() for higher speed */
  343.      /* (for HAM6 encoding only 4097 bytes are needed...)        */
  344.      if(!(ColorCache = malloc(262145)))
  345.        pm_error("Out of memory allocating the color cache.\n");
  346.  
  347.      /* the coded_rowbuf is needed by the IFF encoder */
  348.      if(!(coded_rowbuf = (unsigned char *)malloc(RowBytes(cols))))
  349.        pm_error("Out of memory allocating coded_rowbuf.\n");
  350.      for(i=RowBytes(cols)-1; i>=0; i--) coded_rowbuf[i]=0;
  351.  
  352.      /* write the FORM chunk */
  353.      IFFError = PushChunk(iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN);
  354.      if(IFFError) pm_error("Error writing FORM chunk.\n");
  355.      
  356.      /* initialize the BMHD chunk */
  357.      ilbm.Bmhd.w = cols;
  358.      ilbm.Bmhd.h = rows;             /* Width, height in pixels */
  359.      ilbm.Bmhd.x = 0;
  360.      ilbm.Bmhd.y = 0;                /* x, y position for this bitmap  */
  361.      ilbm.Bmhd.nPlanes = NumPlanes;  /* # of planes (not including mask) */
  362.      ilbm.Bmhd.masking = mskNone;   
  363.      ilbm.Bmhd.compression = cmpByteRun1;   
  364.      ilbm.Bmhd.flags = BMHDF_CMAPOK;        /* CMAP has 8 significant bits */
  365.      ilbm.Bmhd.transparentColor = 0; 
  366.      ilbm.Bmhd.xAspect = cols;         
  367.      ilbm.Bmhd.yAspect = rows;       /* xAspect, yAspect */
  368.      ilbm.Bmhd.pageWidth = cols;
  369.      ilbm.Bmhd.pageHeight = rows;    /* pageWidth, pageHeight */
  370.   
  371.      /* write the BMHD chunk */   
  372.      IFFError = putbmhd(iff, &ilbm.Bmhd);
  373.      if(IFFError) pm_error("Error writing BMHD chunk.\n");
  374.   
  375.      if(GfxEnable) InitDisplay(cols, rows, Mode, NumPlanes);
  376.    }
  377.    
  378.    if(Mode == HAM8 || Mode == HAM6)
  379.    { 
  380.      /* fill in the ColorTable in B R G order */
  381.      /* (this is better for HAM encoding)     */       
  382.      for(i=0; i<NumColors; i++)
  383.      {
  384.        ColorTable[i*3]   = PPM_GETB(colormap[i].color);
  385.        ColorTable[i*3+1] = PPM_GETR(colormap[i].color);
  386.        ColorTable[i*3+2] = PPM_GETG(colormap[i].color);
  387.        if(!jpegAGA)
  388.          SetDisplayColor(i, PPM_GETR(colormap[i].color) << ColorShift,
  389.                             PPM_GETG(colormap[i].color) << ColorShift,
  390.                             PPM_GETB(colormap[i].color) << ColorShift);
  391.      }
  392.      free(colormap); /* we don't need the colormap any more */
  393.      colormap = NULL;
  394.  
  395.      if(jpegAGA)
  396.      {
  397.        unsigned short MagicNumber = 0x1203; /* guess what this means! */
  398.        int Reserved=0; 
  399.        unsigned char color;
  400.   
  401.        ColorMapFile = fopen(ILBMfile, "w");
  402.        
  403.        if(!ColorMapFile)
  404.        {
  405.          char *MapDir;
  406.          MapDir = getenv("MAPDIR");
  407.          if(MapDir && (strlen(MapDir) != 0))
  408.          {
  409.            char *MapDirName;
  410.            int pos,i;
  411.            MapDirName = malloc(strlen(MapDir)+strlen(ILBMfile)+5); /* worst case */
  412.            if(!MapDirName) pm_error("Out of memory.\n");
  413.            strcpy(MapDirName, MapDir);
  414.  
  415.            i = strlen(MapDirName);
  416.            if(MapDirName[i-1] != '/' && MapDirName[i-1] != ':')
  417.            {
  418.              strcat(MapDirName, "/");
  419.              i++;
  420.            }
  421.            i = strlen(ILBMfile);
  422.            while(i > 0 && ILBMfile[i-1] != '/' && ILBMfile[i-1] != ':') i--;
  423.            strcat(MapDirName, &ILBMfile[i]);
  424.            ColorMapFile = fopen(MapDirName, "w");
  425.            if(ColorMapFile) pm_message("Writing mapfile: %s\n", MapDirName);
  426.          }
  427.        }
  428.        if(!ColorMapFile) pm_error("Could not open color map file for jpegAGA.\n");
  429.  
  430.        if(fwrite(&MagicNumber, 2, 1, ColorMapFile) != 1) pm_error("Write error.\n");
  431.        if(fwrite(&Reserved,    4, 1, ColorMapFile) != 1) pm_error("Write error.\n");     
  432.        if(fwrite(ColorTable,  64*3, 1, ColorMapFile) != 1) pm_error("Write error.\n");
  433.        pm_message("Colormap file for jpegAGA created.\n");
  434.        ppmCleanUp();
  435.        return 0;
  436.      }
  437.  
  438.      memset(ColorCache, 0, 262145); /* clear the color cache */          
  439.  
  440.      do
  441.      {
  442.        int y;
  443.        rowcnt=0;
  444.        
  445.        /* if we don't need an additional color the color cache */
  446.        /* will remain valid and should not be cleared          */
  447.  
  448.        memset(ColorCache, 0, 262145); /* clear the color cache */
  449.    
  450.  
  451.        if(!readall)
  452.        {
  453.          rewind(fppm);
  454.          ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);
  455.        }
  456.  
  457.        /* if we have all colors we can write the CMAP chunk */
  458.        if(NumColors == ColorRegMax+1)
  459.        {
  460.          IFFError = PushChunk(iff, 0, ID_CMAP, (ColorRegMax+1)*3);
  461.          if(IFFError) pm_error("Error writing CMAP header.\n");
  462.  
  463.          for( i = 0; i <= ColorRegMax; i++) 
  464.          {
  465.            ColorRegister cmapReg;
  466.            cmapReg.red   = ColorTable[i*3+1] << ColorShift;   /* red */
  467.            cmapReg.green = ColorTable[i*3+2] << ColorShift;   /* green */
  468.            cmapReg.blue  = ColorTable[i*3]   << ColorShift;   /* blue */
  469.            IFFError = WriteChunkBytes(iff, (UBYTE *)&cmapReg, 3);
  470.            if(IFFError!=3) pm_error("Error writing CMAP chunk.\n");
  471.          }
  472.          IFFError = PopChunk(iff); /* close CMAP */
  473.          if(IFFError) pm_error("Error closing CMAP.\n");
  474.  
  475.          /* write the CAMG chunk */
  476.          if(SMR)
  477.          {
  478.            ilbm.camg = SMR_DisplayID;
  479.          }
  480.          else
  481.          {
  482.            if(VGAenable)
  483.            {
  484.              if(cols > 370 || rows > 260)
  485.              {
  486.                ilbm.camg = VGAPRODUCTHAM_KEY;
  487.              }
  488.              else
  489.              {
  490.                ilbm.camg = VGALORESHAMDBL_KEY;
  491.              }
  492.            }
  493.            else
  494.            {
  495.              ilbm.camg = HAM;
  496.              if(cols > 370) ilbm.camg = ilbm.camg | HIRES;
  497.              if(rows > 280) ilbm.camg = ilbm.camg | LACE;
  498.            }
  499.          }
  500.          IFFError = putcamg(iff, &ilbm.camg);
  501.          if(IFFError) pm_error("Error writing CAMG chunk.\n");
  502.  
  503.          /* start with the BODY chunk */
  504.          IFFError = PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
  505.          if(IFFError) pm_error("Error writing BODY header.\n");
  506.        }
  507.  
  508.        /* set a dummy value for AbsMaxError                          */
  509.        /* it will contain the maximum error for the complete picture */ 
  510.        AbsMaxError=0;
  511.   
  512.        for(y=0; y<rows; y++)
  513.        {
  514.          pixel *nextrow;          
  515.  
  516.          MaxError = 0;         
  517.            
  518.          nextrow = next_pixrow(fppm, y, ColorShift);
  519.           
  520.          if(AbortCheck()) pm_error("^C\n");
  521.  
  522.          EncodeHAM(nextrow, hamarray, ColorTable, NumColors*3, (short)cols);
  523.  
  524.          
  525.          /* remember the color of the pixel with the maximum error */
  526.          /* even if MaxError == 0 we will get a valid entry in the */
  527.          /* colormap but it will not be used by the picture        */           
  528.          if(MaxError > AbsMaxError)
  529.          {
  530.            MaxErrorXPos = MaxErrorPos;
  531.            MaxErrorYPos = y;
  532.            AbsMaxError = MaxError;
  533.  
  534.            /* use the color of the pixel with the maximum error as */
  535.            /* a ColorTable entry                                   */
  536.            /* we will have to recompute the picture if we want to  */
  537.            /* use the additional color                             */
  538.            if(NumColors <= ColorRegMax)
  539.            {
  540.              ColorTable[NumColors*3]   = PPM_GETB(pixrow[MaxErrorXPos]);
  541.              ColorTable[NumColors*3+1] = PPM_GETR(pixrow[MaxErrorXPos]);
  542.              ColorTable[NumColors*3+2] = PPM_GETG(pixrow[MaxErrorXPos]);
  543.            }        
  544.          }
  545.  
  546.          /* if all colors are set we can write our row to the BODY chunk */
  547.          if(NumColors == ColorRegMax+1) 
  548.          {
  549.            encode_row(hamarray, cols, NumPlanes);
  550.          }
  551.          DisplayRow(hamarray, cols, y);
  552.        }
  553.  
  554.        /* this is only for debugging purposes */
  555.        if(NumColors <= ColorRegMax)
  556.        {
  557.          #ifdef DEBUG
  558.          pm_message("Max Error: %hd ", AbsMaxError);
  559.          #endif
  560.          if(AbsMaxError == 0)
  561.          {
  562.            printf("\n");
  563.          }
  564.          else
  565.          {
  566.            #ifdef DEBUG
  567.            pm_message("Color %hd, XPos: %hd, YPos: %hd\n", NumColors, MaxErrorXPos, MaxErrorYPos);
  568.            #endif
  569.          }
  570.        }
  571.        SetDisplayColor(NumColors, ColorTable[NumColors*3+1] << ColorShift,
  572.                                   ColorTable[NumColors*3+2] << ColorShift,
  573.                                   ColorTable[NumColors*3]   << ColorShift);
  574.        NumColors = NumColors + 1; 
  575.     
  576.      /* finish if we have set all colors */
  577.      } while(NumColors <= ColorRegMax+1);
  578.  
  579.  
  580.      #ifdef DEBUG
  581.      pm_message("Max Error: %hd, XOffset: %hd YOffset: %hd\n",
  582.                AbsMaxError, MaxErrorXPos, MaxErrorYPos);
  583.  
  584.      pm_message("Colortable: ");
  585.      for(i=0; i<=ColorRegMax; i++)
  586.      {
  587.        pm_message("%hd,%hd,%hd ",ColorTable[i*3],
  588.                    ColorTable[i*3+1],ColorTable[i*3+2]);
  589.      }
  590.      pm_message("\n");
  591.      #endif
  592.  
  593.      /* close the BODY chunk */
  594.      IFFError = PopChunk(iff); 
  595.      if(IFFError) pm_message("Error closing the BODY chunk.\n");
  596.    }
  597.    
  598.  
  599.    else if(Mode == COLORMAP)
  600.    { 
  601.      /* if floyd is nonzero we will use Floyd-Steinberg dithering */
  602.      int row, fs_direction;
  603.      register int col, limitcol, ind;
  604.      register pixel *pP;
  605.      register long sg, sr, sb, err;
  606.      long *temperr;
  607.  
  608.      /*
  609.      ** map the colors in the image to their closest match in the
  610.      ** new colormap, and write 'em out.
  611.      */
  612.        
  613.      pm_message( "Mapping image to new colors...\n" );
  614.  
  615.      /* write the CMAP chunk */
  616.      IFFError = PushChunk(iff, 0, ID_CMAP, NumColors*3);
  617.      if(IFFError) pm_error("Error writing CMAP header.\n");
  618.      for( i = 0; i < NumColors; i++) 
  619.      {
  620.        ColorRegister cmapReg;
  621.        cmapReg.red   = PPM_GETR( colormap[i].color );   /* red   */
  622.        cmapReg.green = PPM_GETG( colormap[i].color );   /* green */
  623.        cmapReg.blue  = PPM_GETB( colormap[i].color );   /* blue  */
  624.        SetDisplayColor(i, cmapReg.red, cmapReg.green, cmapReg.blue);
  625.        IFFError = WriteChunkBytes(iff, (UBYTE *)&cmapReg, 3);
  626.        if(IFFError!=3) pm_error("Error writing CMAP chunk.\n");
  627.      }
  628.      IFFError = PopChunk(iff); /* close CMAP */
  629.      if(IFFError) pm_error("Error closing CMAP.\n");
  630.  
  631.      /* write the CAMG chunk */
  632.      if(SMR)
  633.      {
  634.        ilbm.camg = SMR_DisplayID;
  635.      }
  636.      else
  637.      {
  638.        ilbm.camg = 0;
  639.        if(VGAenable)
  640.        {
  641.          if(cols > 370 || rows > 260)
  642.            ilbm.camg = VGAPRODUCT_KEY;
  643.          else
  644.            ilbm.camg = VGALORESDBL_KEY;
  645.        }
  646.        else
  647.        {
  648.          if(cols > 370) ilbm.camg = ilbm.camg | HIRES;
  649.          if(rows > 280) ilbm.camg = ilbm.camg | LACE;
  650.        }
  651.      }
  652.      IFFError = putcamg(iff, &ilbm.camg);
  653.      if(IFFError) pm_error("Error writing CAMG chunk.\n");
  654.  
  655.      /* start with the BODY chunk */
  656.      IFFError = PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
  657.      if(IFFError) pm_error("Error writing BODY header.\n");
  658.  
  659.      rowcnt=0;
  660.      if(!readall)
  661.      {
  662.        rewind(fppm);
  663.        ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);       
  664.      }
  665.  
  666.      if ( floyd )
  667.      {
  668.        fs_direction = 1;
  669.      }
  670.      for ( row = 0; row < rows; ++row )
  671.      {
  672.        /* PLProgress(row, rows); */
  673.        if(AbortCheck()) pm_error("^C\n");
  674.        if ( floyd )
  675.          for ( col = 0; col < cols + 2; ++col )
  676.            nextrerr[col] = nextgerr[col] = nextberr[col] = 0;
  677.        if ( ( ! floyd ) || fs_direction )
  678.        {
  679.          col = 0;
  680.          limitcol = cols;
  681.          /* pP = pixels[row]; */
  682.          pP = next_pixrow(fppm, row, ColorShift);
  683.        }
  684.        else
  685.        {
  686.          col = cols - 1;
  687.          limitcol = -1;
  688.          /* pP = &(pixels[row][col]); */
  689.          pP = &(next_pixrow(fppm, row, ColorShift)[col]);
  690.        }
  691.        do
  692.        {
  693.          if ( floyd )
  694.          {
  695.            /* Use Floyd-Steinberg errors to adjust actual color. */
  696.            sr = PPM_GETR(*pP) + thisrerr[col + 1] / FS_SCALE;
  697.            sg = PPM_GETG(*pP) + thisgerr[col + 1] / FS_SCALE;
  698.            sb = PPM_GETB(*pP) + thisberr[col + 1] / FS_SCALE;
  699.            if ( sr < 0 ) sr = 0;
  700.            else if ( sr > maxval ) sr = maxval;
  701.            if ( sg < 0 ) sg = 0;
  702.            else if ( sg > maxval ) sg = maxval;
  703.            if ( sb < 0 ) sb = 0;
  704.            else if ( sb > maxval ) sb = maxval;
  705.            PPM_ASSIGN( *pP, sr, sg, sb );
  706.          }
  707.  
  708.          /* use the assembler subroutine for the colormap search */
  709.          /* this will consume most of the CPU time               */                     
  710.          ind = MapColorASM(colormap, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP),
  711.                            NumColors);
  712.            
  713.          /* compare the results of the ASM versus the C routine */
  714.          /* if they differ the ASM routine has a bug...         */
  715.          /* (we don't need them because they are the same now)  */
  716.          #ifdef DEBUG_ASM
  717.          if(ind != MapColor(colormap, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP),
  718.                             NumColors))
  719.            pm_message("Diff: row %d col %d  r %d g %d b %d\n", row,col,
  720.                        (int)PPM_GETR(*pP), (int)PPM_GETG(*pP), (int)PPM_GETB(*pP));
  721.          #endif
  722.  
  723.          if ( floyd )
  724.          {
  725.            /* Propagate Floyd-Steinberg error terms. */
  726.            if ( fs_direction )
  727.            {
  728.              err = ( sr - (long) PPM_GETR( colormap[ind].color ) ) * FS_SCALE;
  729.              thisrerr[col + 2] += ( err * 7 ) / 16;
  730.              nextrerr[col    ] += ( err * 3 ) / 16;
  731.              nextrerr[col + 1] += ( err * 5 ) / 16;
  732.              nextrerr[col + 2] += ( err     ) / 16;
  733.              err = ( sg - (long) PPM_GETG( colormap[ind].color ) ) * FS_SCALE;
  734.              thisgerr[col + 2] += ( err * 7 ) / 16;
  735.              nextgerr[col    ] += ( err * 3 ) / 16;
  736.              nextgerr[col + 1] += ( err * 5 ) / 16;
  737.              nextgerr[col + 2] += ( err     ) / 16;
  738.              err = ( sb - (long) PPM_GETB( colormap[ind].color ) ) * FS_SCALE;
  739.              thisberr[col + 2] += ( err * 7 ) / 16;
  740.              nextberr[col    ] += ( err * 3 ) / 16;
  741.              nextberr[col + 1] += ( err * 5 ) / 16;
  742.              nextberr[col + 2] += ( err     ) / 16;
  743.            }
  744.            else
  745.            {
  746.              err = ( sr - (long) PPM_GETR( colormap[ind].color ) ) * FS_SCALE;
  747.              thisrerr[col    ] += ( err * 7 ) / 16;
  748.              nextrerr[col + 2] += ( err * 3 ) / 16;
  749.              nextrerr[col + 1] += ( err * 5 ) / 16;
  750.              nextrerr[col    ] += ( err     ) / 16;
  751.              err = ( sg - (long) PPM_GETG( colormap[ind].color ) ) * FS_SCALE;
  752.              thisgerr[col    ] += ( err * 7 ) / 16;
  753.              nextgerr[col + 2] += ( err * 3 ) / 16;
  754.              nextgerr[col + 1] += ( err * 5 ) / 16;
  755.              nextgerr[col    ] += ( err     ) / 16;
  756.              err = ( sb - (long) PPM_GETB( colormap[ind].color ) ) * FS_SCALE;
  757.              thisberr[col    ] += ( err * 7 ) / 16;
  758.              nextberr[col + 2] += ( err * 3 ) / 16;
  759.              nextberr[col + 1] += ( err * 5 ) / 16;
  760.              nextberr[col    ] += ( err     ) / 16;
  761.            }
  762.          }
  763.  
  764.          /* *pP = colormap[ind].color; */
  765.          hamarray[col] = (unsigned char)ind;
  766.  
  767.          if ( ( ! floyd ) || fs_direction )
  768.          {
  769.            ++col;
  770.            ++pP;
  771.          }
  772.          else
  773.          {
  774.            --col;
  775.            --pP;
  776.          }
  777.        }
  778.        while ( col != limitcol );
  779.  
  780.        if ( floyd )
  781.        {
  782.          temperr = thisrerr;
  783.          thisrerr = nextrerr;
  784.          nextrerr = temperr;
  785.          temperr = thisgerr;
  786.          thisgerr = nextgerr;
  787.          nextgerr = temperr;
  788.          temperr = thisberr;
  789.          thisberr = nextberr;
  790.          nextberr = temperr;
  791.          fs_direction = ! fs_direction;
  792.        }
  793.  
  794.        /* ppm_writeppmrow( stdout, pixels[row], cols, maxval, 0 ); */
  795.        /* write one row to the BODY chunk */
  796.        encode_row(hamarray, cols, NumPlanes);
  797.        DisplayRow(hamarray, cols, row);
  798.      }
  799.      IFFError = PopChunk(iff); /* close the BODY */
  800.      if(IFFError) pm_error("Error closing the BODY chunk.\n");
  801.    }       
  802.  }
  803.  
  804.  closeifile((struct ParseInfo *)&ilbm);
  805.  ppmCleanUp();
  806.  return 0;
  807. }
  808.  
  809.  
  810. /* free all resources used by this module */
  811. void ppmCleanUp(void)
  812. {
  813.  CloseDisplay();
  814.  if(colormap) free(colormap);
  815.  if(pgmrow) pgm_freerow(pgmrow); 
  816.  if(coded_rowbuf) free(coded_rowbuf);
  817.  if(CompressBuffer) free(CompressBuffer);
  818.  if(ColorCache) free(ColorCache);
  819.  if(chv) free(chv);
  820.  if(hamarray) free(hamarray);
  821.  if(pixels)
  822.  {
  823.    ppm_freearray(pixels, rows);
  824.  } 
  825.  else
  826.  {
  827.    if(pixrow) pbm_freerow(pixrow);
  828.  }
  829.  if(fppm) fclose(fppm);
  830.  
  831.  if(jpegAGA)
  832.  {
  833.    if(ColorMapFile)
  834.    {
  835.      fclose(ColorMapFile);
  836.      ColorMapFile = NULL;
  837.    }
  838.  }
  839.  else
  840.  {
  841.    if(ilbm.ParseInfo.opened)
  842.    {
  843.      closeifile((struct ParseInfo *)&ilbm);
  844.      remove(ILBMfile);
  845.    }
  846.    if(ilbm.ParseInfo.iff) FreeIFF(ilbm.ParseInfo.iff);
  847.  }
  848. }
  849.  
  850.  
  851.  
  852. /* convert one row from chunky to planar, compress it, */
  853. /* and write it to the BODY chunk                      */
  854.  
  855. /* encode algorithm by Johan Widen (jw@jwdata.se) */
  856. /* modified by Günther Röhrich */
  857.  
  858. const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
  859.  
  860. static void
  861. encode_row(UBYTE *row, int cols, int nPlanes)
  862. {
  863.  register int plane, col;
  864.  int bytes;
  865.  LONG packedRowBytes;
  866.  BYTE *source;
  867.  BYTE *destination;
  868.  
  869.  bytes = RowBytes(cols);
  870.  
  871.  /* Encode and write raw bytes in plane-interleaved form. */
  872.  for( plane = 0; plane < nPlanes; plane++ ) 
  873.  {
  874.    int mask, cbit, wr;
  875.    unsigned char *cp;
  876.    UBYTE *rp;
  877.  
  878.    mask = 1 << plane;
  879.    cbit = -1;
  880.    cp = coded_rowbuf-1;
  881.    rp = row;
  882.    for( col = 0; col < cols; col++, cbit--, rp++ ) 
  883.    {
  884.      if( cbit < 0 ) 
  885.      {
  886.        cbit = 7;
  887.        *++cp = 0;
  888.      }
  889.      if( *rp & mask )
  890.        *cp |= bit_mask[cbit];
  891.    }
  892.    /* wr = fwrite(coded_rowbuf, 1, bytes, stdout); */
  893.  
  894.    /* compress the row */
  895.    source = coded_rowbuf;
  896.    destination = CompressBuffer;
  897.    packedRowBytes = packrow(&source, &destination, bytes);
  898.  
  899.    /* write the compressed row to the BODY chunk */  
  900.    IFFError = WriteChunkBytes(iff, CompressBuffer, packedRowBytes); 
  901.    if(IFFError!=packedRowBytes) pm_error("Error writing BODY chunk.\n");
  902.  }
  903. }
  904.  
  905.  
  906. #ifdef DEBUG_ASM
  907. /* this is the C version of the colormap search routine */
  908. /* (it is now replaced by the ASM version)              */
  909.  
  910. /* search colormap for closest match. */
  911. int MapColor(colorhist_vector colormap, pixval r, pixval g, pixval b, 
  912.              int newcolors)
  913.  int ind;
  914.  register int i, r1, g1, b1, r2, g2, b2;
  915.  register long dist, newdist;
  916.  r1 = r;
  917.  g1 = g;
  918.  b1 = b;
  919.  dist = 2000000000;
  920.  for ( i = 0; i < newcolors; ++i )
  921.  {
  922.    r2 = PPM_GETR( colormap[i].color );
  923.    g2 = PPM_GETG( colormap[i].color );
  924.    b2 = PPM_GETB( colormap[i].color );
  925.    newdist = ( r1 - r2 ) * ( r1 - r2 ) +
  926.              ( g1 - g2 ) * ( g1 - g2 ) +
  927.              ( b1 - b2 ) * ( b1 - b2 );
  928.    if ( newdist < dist )
  929.    {
  930.      ind = i;
  931.      dist = newdist;
  932.    }
  933.  }
  934.  return ind;
  935. }
  936. #endif
  937.  
  938.  
  939.